package com.javaspeak.concurrency.cas.atomicstampedreference;

import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @author John Dickerson
 */
public class AtomicStampedReferenceUpdater {

    private Long time = Long.decode( "1" );

    private AtomicStampedReference<Long> atomicStampedReference =
        new AtomicStampedReference<Long>( time, 1 );

    
    public Long setTime( Long time ){

        int[] oldStamp = new int[1];

        while ( true ){

            Long oldTime = atomicStampedReference.get( oldStamp );

            int newStamp = oldStamp[ 0 ] + 1;

            if ( atomicStampedReference.compareAndSet(
                    oldTime, time, oldStamp[ 0 ], newStamp ) ){

                return oldTime;
            }
        }
    }


    public Long getTime( int[] updatedStamp ){

        int[] stamp = new int[1];
        Long time = atomicStampedReference.get( stamp );

        updatedStamp[ 0 ] = stamp[ 0 ];

        return time;
    }



    public static void main(String[] args) {

        AtomicStampedReferenceUpdater atomicStampedReferenceUpdater =
            new AtomicStampedReferenceUpdater();

        Long oldTime =
            atomicStampedReferenceUpdater.setTime( Long.valueOf( 1000 ) );

        System.out.println( "oldTime = " + oldTime );

        int[] version = new int[ 1 ];
        Long newTime = atomicStampedReferenceUpdater.getTime( version );

        System.out.println(
            "newTime = " + newTime + ", version: " + version[ 0 ] );
    }
}
